﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;

using System.IO;
using System.Xml;
using System.Collections.ObjectModel;
using BingMapBrowser.ViewModel;
using Microsoft.Maps.MapControl;

//Feedbacks
//1.  Form should be maximizable.
//2.  Map should zoom at the mentioned location.
//3.  Configurable to show records of only one type: May be a checkbox for each type.
//4.  Improve performance??
//5.  Show only near records if applied.
//6.  Configurable to use KM or Miles.
//7.  Auto-refresh??
//8.  Handle https warning. Consider using http if CRM is http.
//9.  Improve error logging??
//10. Better integration on entity forms??
//11. Improve documentation.
///////////////////////////////////////////////////////////////////////////////////////////
namespace BingMapBrowser
{
	public partial class MainPage : UserControl
	{
		EntityViewModel vm;
		Location defaultMapLocation;
		double defaultMapZoomLevel;
		bool isNearDistanceInMiles = true;

		public MainPage()
		{
			InitializeComponent();
			vm = new EntityViewModel();
			this.DataContext = vm;
			//nearRecordsGrid.ItemsSource = vm.NearRecords;
			string bingKey = SilverlightUtility.BingMapKey();
			if (String.IsNullOrEmpty(bingKey))
			{
				MessageBox.Show("Please set bing map key in BingMapKeys.xml web resource.");
				return;
			}
			//Set Bing Map key
			Microsoft.Maps.MapControl.ApplicationIdCredentialsProvider credP = new Microsoft.Maps.MapControl.ApplicationIdCredentialsProvider(bingKey);
			this.bingMap.CredentialsProvider = credP;

			//Set Configuration file
			Uri serverUrl = SilverlightUtility.GetServerBaseUrl();
			if (String.IsNullOrEmpty(serverUrl.ToString()))
			{
				MessageBox.Show("Error occured while retrieving server url.\nMake sure silverlight is hosted in the html webresource.");
				return;
			}

			string configFileName = SilverlightUtility.GetConfigFile();
			if (String.IsNullOrEmpty(configFileName))
			{
				configFileName = @"new_BingMapConfig.xml";
			}
			SilverlightUtility.Trace("ServerUrl: " + serverUrl);
			SilverlightUtility.Trace("Config File Name: " + configFileName);
			Uri url = SilverlightUtility.CombineUrl(serverUrl, "WebResources/" + configFileName);
			SilverlightUtility.Trace("Web resource url: " + url);
			WebClient client = new WebClient();
			client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
			client.DownloadStringAsync(url);

		}

		void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
		{
			MyEntity[] metadata = null;
			if (e.Error == null)
			{
				using (StringReader stream = new StringReader(e.Result))
				{
					using (XmlReader reader = XmlReader.Create(stream))
					{
						metadata = GetMetadata(reader);
						if (null != defaultMapLocation)
						{
							this.bingMap.Center = defaultMapLocation;
							this.bingMap.ZoomLevel = defaultMapZoomLevel;
						}
						SilverlightUtility.Trace("Loaded Config file successfuly");
					}
				}
				try
				{
					vm.QueryEntity(metadata);
					LoadFiltersPanel();
					LoadNearRecordsPanel();
				}
				catch (Exception ex)
				{
					MessageBox.Show("Error loading the entities. Make sure you are online. " + ex.Message);
				}
			}
		}

		private void LoadFiltersPanel()
		{
			EntityPicker.ItemsSource = vm.Metadata;
			EntityPicker.DisplayMemberPath = "EntityDisplayName";
			foreach (var metadata in vm.Metadata)
			{
				StackPanel panel = new StackPanel();
				panel.Orientation = Orientation.Horizontal;
				//panel.SetValue(Grid.RowProperty, 1);
				panel.Visibility = System.Windows.Visibility.Collapsed;
				panel.Name = metadata.EntityDisplayName;
				foreach (Condition condition in metadata.Conditions)
				{
					TextBlock block1 = new TextBlock();
					block1.Margin = new Thickness(10, 0, 0, 0);
					block1.MinWidth = 50;
					Binding binding = new Binding("Text");
					binding.Source = condition;
					binding.Mode = BindingMode.TwoWay;
					block1.SetBinding(TextBlock.TextProperty, binding);

					TextBox box1 = new TextBox();
					box1.MinWidth = 50;
					box1.Margin = new Thickness(5, 0, 0, 0);
					binding = new Binding("Value");
					binding.Source = condition;
					binding.Mode = BindingMode.TwoWay;
					box1.SetBinding(TextBox.TextProperty, binding);

					panel.Children.Add(block1);
					panel.Children.Add(box1);
				}
				filters.Children.Add(panel);
				//LayoutRoot.Children.Add(panel);
			}

		}

		private void LoadNearRecordsPanel()
		{
			
		}

		StackPanel currentVisiblePanel = null;
		private void EntityPicker_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (currentVisiblePanel != null)
			{
				currentVisiblePanel.Visibility = System.Windows.Visibility.Collapsed;
			}
			MyEntity selectedItem = (MyEntity)EntityPicker.SelectedItem;
			foreach (var children in this.filters.Children)
			{
				if (children as StackPanel != null)
				{
					StackPanel panel = (StackPanel)children;
					if(panel.Name.Equals(selectedItem.EntityDisplayName))
					{
						panel.Visibility = System.Windows.Visibility.Visible;
						currentVisiblePanel = panel;
					}
				}
			}
		}

		private void LoadRecords_Click(object sender, RoutedEventArgs e)
		{
			vm.QueryEntity();
		}

		private void loadNearRecordsButton_Click(object sender, RoutedEventArgs e)
		{
			Double dist = Double.Parse(distance.Text);
			vm.GetNearRecords(dist, isNearDistanceInMiles);
		}

		private void bingMap_MouseClick(object sender, Microsoft.Maps.MapControl.MapMouseEventArgs e)
		{
			var location = bingMap.ViewportPointToLocation(e.ViewportPoint);
			vm.ClickedLocation = location;
			latLongLabel.Text = String.Format("{0:0.000}, {1:0.000}", location.Latitude, location.Longitude);
		}

		private void CloseButton_Click(object sender, RoutedEventArgs e)
		{
			detailsPane.Visibility = System.Windows.Visibility.Collapsed;
		}

		private void EntityPushPin_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			try
			{
				var d = ((FrameworkElement)sender).DataContext as MyEntity;
				Pushpin pushPin = (Pushpin)sender;
				this.bingMap.SetView(d.Address.Location, d.ToolTip.ZoomLevel);

				fullRecordView.DataContext = d;
				fullRecordView.listGrid.ItemsSource = d.ListItems;
				fullRecordView.linksBox.ItemsSource = d.Links;
				fullRecordView.formButton.Foreground = pushPin.Background;
				detailsPane.Visibility = Visibility.Visible;
			}
			catch (Exception ex)
			{
				MessageBox.Show("Error Occured in Pushpin Clicked:\nError Message: " + ex.Message);
			}
		}

		private void nearRecordsGrid_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
		{
			MyEntity d = nearRecordsGrid.SelectedItem as MyEntity;
			if (d == null)
			{
				MessageBox.Show("Please select the row first and then right click to open the record's form.");
				return;
			}
			d.OpenForm();
		}

		#region Private helpers
		private MyEntity[] GetMetadata(XmlReader reader)
		{
			List<MyEntity> AllEntities = new List<MyEntity>();
			MyEntity CurrentEntity = null;
			int conditionCount = 0;
			int linkCount = 0;
			int listItemsCount = 0;
			try
			{
				while (reader.Read())
				{
					if (reader.NodeType == XmlNodeType.Element)
					{
						//Handle all global settings under this if condition
						if (reader.Name.Equals("globalsettings", StringComparison.OrdinalIgnoreCase))
						{
							reader.ReadToFollowing("defaultMapLocation");
							if (true == reader.MoveToFirstAttribute())
							{
								string location = reader.Value;
								string[] latLong = location.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
								defaultMapLocation = new Location(Double.Parse(latLong[0]), Double.Parse(latLong[1]));
							}
							if (true == reader.MoveToNextAttribute())
							{
								defaultMapZoomLevel = Double.Parse(reader.Value);
							}

							reader.ReadToFollowing("nearDistanceUnit");
							if (true == reader.MoveToFirstAttribute())
							{
								isNearDistanceInMiles = string.Equals("miles", reader.Value) || string.Equals("mile", reader.Value) ? true : false;
							}
						}

						if (reader.Name.Equals("entity", StringComparison.OrdinalIgnoreCase))
						{
							CurrentEntity = new MyEntity();
							conditionCount = 0;
							linkCount = 0;
							listItemsCount = 0;
							AllEntities.Add(CurrentEntity);

							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.EntityName = reader.Value;
							}
							if (true == reader.MoveToNextAttribute())
							{
								CurrentEntity.EntityDisplayName = reader.Value;
							}
						}

						if (reader.Name.Equals("address", StringComparison.OrdinalIgnoreCase))
						{
							reader.ReadToFollowing("latitude");
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.Address.Latitude = reader.Value;
							}

							reader.ReadToFollowing("longitude");
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.Address.Longitude = reader.Value;
							}
						}

						if (reader.Name.Equals("filters", StringComparison.OrdinalIgnoreCase))
						{
							//Do nothing
						}

						if (reader.Name.Equals("fetchXml", StringComparison.OrdinalIgnoreCase))
						{
							CurrentEntity.FetchXml = reader.ReadInnerXml();
							//Do nothing
						}

						if (reader.Name.Equals("mapcondition", StringComparison.OrdinalIgnoreCase))
						{
							CurrentEntity.Conditions.Add(new Condition());
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.Conditions[conditionCount].Text = reader.Value;
							}

							reader.ReadToFollowing("condition");
							CurrentEntity.Conditions[conditionCount].Expression = reader.ReadOuterXml();

							reader.ReadToFollowing("value");
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.Conditions[conditionCount].Type = reader.Value;
							}
							if (true == reader.MoveToNextAttribute())
							{
								CurrentEntity.Conditions[conditionCount].Value = reader.Value;
							}
							conditionCount++;
						}

						if (reader.Name.Equals("displaypanel", StringComparison.OrdinalIgnoreCase))
						{
							//Do Nothing
						}

						if (reader.Name.Equals("links", StringComparison.OrdinalIgnoreCase))
						{
							//Do Nothing
						}

						if (reader.Name.Equals("lists", StringComparison.OrdinalIgnoreCase))
						{
							//Do Nothing
						}

						if (reader.Name.Equals("link", StringComparison.OrdinalIgnoreCase))
						{
							CurrentEntity.Links.Add(new Link());
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.Links[linkCount].Text = reader.Value;
							}

							reader.ReadToFollowing("field");

							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.Links[linkCount].FieldName = reader.Value;
							}

							linkCount++;
						}

						if (reader.Name.Equals("listitem", StringComparison.OrdinalIgnoreCase))
						{
							CurrentEntity.ListItems.Add(new List());
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.ListItems[listItemsCount].Text = reader.Value;
							}

							reader.ReadToFollowing("field");
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.ListItems[listItemsCount].FieldName = reader.Value;
							}

							listItemsCount++;
						}

						if (reader.Name.Equals("tooltip", StringComparison.OrdinalIgnoreCase))
						{
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.ToolTip.Text = reader.Value;
							}

							reader.ReadToFollowing("field");
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.ToolTip.FieldName = reader.Value;
							}

							reader.ReadToFollowing("color");
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.ToolTip.Color = reader.Value;
							}

							reader.ReadToFollowing("zoomlevel");
							if (true == reader.MoveToFirstAttribute())
							{
								CurrentEntity.ToolTip.ZoomLevel = Double.Parse(reader.Value);
							}
						}
					}
				}
			}
			catch (Exception e)
			{
				MessageBox.Show("Exception Occured: " + e.Message);
			}
			return AllEntities.ToArray();
		}
		#endregion
	}
}
